package la.iok.hzsvn.lewin.movie.service;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import la.iok.hzsvn.lewin.movie.config.DfsProperties;
import la.iok.hzsvn.lewin.movie.core.RoleEnum;
import la.iok.hzsvn.lewin.movie.core.Token;
import la.iok.hzsvn.lewin.movie.core.exception.ErrorCode;
import la.iok.hzsvn.lewin.movie.entity.AppPackage;
import la.iok.hzsvn.lewin.movie.entity.AppPackageItem;
import la.iok.hzsvn.lewin.movie.mapper.AppPackageMapper;
import la.iok.hzsvn.lewin.movie.model.AppPackageParam;
import la.iok.hzsvn.lewin.movie.model.Version;
import la.iok.hzsvn.lewin.mybatis.model.PageVo;
import la.iok.hzsvn.lewin.mybatis.service.BaseServiceImpl;
import la.iok.hzsvn.share.annotations.NotNull;
import la.iok.hzsvn.share.annotations.Nullable;
import la.iok.hzsvn.share.dfs.exception.DfsException;
import la.iok.hzsvn.share.tools.zip.ZipUtils;
import la.iok.hzsvn.share.utils.*;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.List;

@Service
public class AppPackageServiceImpl extends BaseServiceImpl<AppPackage, AppPackageMapper,Long> implements AppPackageService {
    private final AppPackageItemService appPackageItemService;
    private final DfsProperties dfsProperties;
    public AppPackageServiceImpl(AppPackageMapper mapper,
                                 AppPackageItemService appPackageItemService, DfsProperties dfsProperties) {
        super(mapper);
        this.appPackageItemService = appPackageItemService;
        this.dfsProperties = dfsProperties;
    }

    @Override
    public Long save(@NotNull Token token, @NotNull AppPackageParam param) {
        token.validAnyAuthority(RoleEnum.Admin);
        String appName = ErrorCode.PROPERTY_CHECK_ERROR.assertNotBlank(param.getAppName(),"名称","应用名称不能为空");
        String packageType = ErrorCode.PROPERTY_CHECK_ERROR.assertNotBlank(param.getPackageType(),"类别","程序包的类别不能为空");
        String productType = ErrorCode.PROPERTY_CHECK_ERROR.assertNotBlank(param.getProductType(),"产品分类","产品分类不能为空");
        String versionName = ErrorCode.PROPERTY_CHECK_ERROR.assertNotBlank(param.getVersionName(),"版本","版本名称不能为空");
        ErrorCode.APP_EXIST_ERROR.assertEqual(0,mapper.exist(appName,packageType,productType,versionName),()->new Object[]{
                String.format("%s-%s-%s-%s",appName,packageType,productType,versionName)
        });
        AppPackage entity = new AppPackage();
        entity.setAppName(appName);
        entity.setPackageType(packageType);
        entity.setProductType(productType);
        entity.setVersionName(versionName);
        entity.setVersionCode(param.getVersionCode());
        insertSelective(entity);
        return entity.getId();
    }

    @Override
    public void delete(Token token, Long id) {
        token.validAnyAuthority(RoleEnum.Admin);
        appPackageItemService.deletePackageItems(id);
        delete(id);
    }

    @Override
    public Version version(String appName, String packageType, String productType) {
        if(StringUtils.isBlank(appName) || StringUtils.isBlank(packageType) || StringUtils.isBlank(productType)){
            return null;
        }
        return mapper.version(appName,packageType,productType);
    }

    @Transactional
    @Override
    public void latest(@NotNull Token token, @Nullable Long id) {
        token.validAnyAuthority(RoleEnum.Admin);
        AppPackage entity = select(id);
        ErrorCode.RECORD_NOT_EXIST.assertNotNull(entity,id);
        //检查每个文件都存在
        appPackageItemService.allFileExist(id);
        mapper.resetLatest(entity.getAppName(),entity.getPackageType(),entity.getProductType());
        update(id,"latest",1);
    }

    @Override
    public PageVo<AppPackage> page(int page, int limit) {
        Page<AppPackage> list = PageHelper.startPage(page,limit);
        selectAll();
        return page(list,item->item);
    }

    @Override
    public void downloadZipPackage(HttpServletResponse response, Long id) {
        AppPackage app = select(id);
        ErrorCode.RECORD_NOT_EXIST.assertNotNull(app,id);
        String root = StringUtils.isBlank(dfsProperties.getTmpPath()) ? PathUtils.getPath() : dfsProperties.getTmpPath();
        root = PathUtils.join(root,"app",String.valueOf(id));
        FileUtils.deleteFile(root,false);
        String appPath = PathUtils.join(root,app.getAppName());
        List<AppPackageItem> list = appPackageItemService.packageFiles(id);
        if(CollectionUtils.isEmpty(list)){
            throw new DfsException("程序包文件为空");
        }
        try {
            for (AppPackageItem item : list) {
                try{
                    appPackageItemService.download2Local(appPath,item);
                }catch (IOException e){
                    throw new DfsException("读取文件" + item.getRelativePath() + "失败",e);
                }
            }
            String downloadFile = null;
            if(list.size() == 1){
                //单个文件不用压缩了
                downloadFile = PathUtils.join(appPath,list.get(0).getRelativePath());
            }else{
                downloadFile = PathUtils.join(root,"app.zip");
                try {
                    ZipUtils.zip(downloadFile,appPath);
                } catch (IOException e) {
                    throw new DfsException("创建压缩包失败",e);
                }
            }
            File file = new File(downloadFile);
            try(OutputStream out = response.getOutputStream();InputStream is = new FileInputStream(file)) {
                response.setContentType("application/x-download;charset=UTF-8");
                String filename = URLEncoder.encode(file.getName(), "UTF-8");
                response.addHeader("Content-Disposition", "attachment;filename=" + filename);
                response.setContentLengthLong(file.length());
                IOUtils.trans(is,out);
                out.flush();
            } catch (IOException e) {
                throw new DfsException("下载压缩包失败",e);
            }
        } finally {
            FileUtils.deleteFile(root,true);
        }
    }
}
